package org.budo.phone.ronglian;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.budo.phone.api.AbstractPhoneApiResponse;
import org.budo.phone.api.PhoneApiResponse;
import org.budo.phone.api.request.*;
import org.budo.phone.api.response.Agent;
import org.budo.phone.api.response.QueryAgentStateResponse;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.mvcs.Mvcs;
import org.budo.support.servlet.util.ResponseUtil;
import org.budo.xml.Xml;
import org.budo.xml.XmlObject;
import org.springframework.util.Base64Utils;
import org.springframework.util.DigestUtils;

import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
public class RonglianApiSupport {
    /**
     * 由子类实现
     */
    protected String findAppSecret(String appKey) {
        throw new UnsupportedOperationException("#42 appKey=" + appKey + ", this=" + this);
    }

    @SuppressWarnings("unchecked")
    protected <T> T apiRequest(HttpServletRequest request, Class<T> type) {
        if (AgentOnWorkRequest.class.equals(type)) {
            return (T) this.agentOnWorkRequest(request);
        }

        if (AgentOffWorkRequest.class.equals(type)) {
            return (T) this.agentOffWorkRequest(request);
        }

        if (AgentReadyRequest.class.equals(type)) {
            return (T) this.agentReadyRequest(request);
        }

        if (IvrDialRequest.class.equals(type)) {
            return (T) this.ivrDialRequest(request);
        }

        if (AgentServiceEndRequest.class.equals(type)) {
            return (T) this.agentServiceEndRequest(request);
        }

        if (QueryAgentStateRequest.class.equals(type)) {
            return (T) this.queryAgentStateRequest(request);
        }

        if (BreakFileRequest.class.equals(type)) {
            return (T) this.breakFileRequest(request);
        }
        throw new RuntimeException("#62 type=" + type);
    }


    /**
     * 返回结果,暂只支持json格式
     *
     * @see https://doc.yuntongxun.com/p/5a533ac73b8496dd00dce025
     * @see https://www.yuntongxun.com/doc/ivr/ivrabout/4_1_1_8.html
     */
    protected void apiResponse(PhoneApiResponse apiResponse) {
        HttpServletResponse servletResponse = Mvcs.getResponse();
        String json = this.toJson(apiResponse);
        ResponseUtil.writeToResponse(servletResponse, json);
    }

    /**
     * 接口认证检查
     */
    protected Boolean checkAuthorization(HttpServletRequest request) {
        String sig = Mvcs.getRequestParameter(request, "sig");
        String authorization = Mvcs.getRequestHeader(request, "Authorization");

        if (StringUtil.isEmpty(authorization) || StringUtil.isEmpty(sig)) {
            log.error("#96 parameterMap=" + JSON.toJSONString(Mvcs.getRequestParameterMap(request)) //
                    + ", headerMap=" + JSON.toJSONString(Mvcs.getRequestHeaderMap(request)) + ", request=" + request);
            this.apiResponse(new AbstractPhoneApiResponse().setStatusCode("auth-check-fail-91"));
            return false;
        }

        byte[] authorizationDecodedBytes = Base64Utils.decodeFromString(authorization);
        String authorizationDecoded = new String(authorizationDecodedBytes);
        String[] appKeyAndTime = authorizationDecoded.split(":");

        String appKey = appKeyAndTime[0];
        String time = appKeyAndTime[1];

        String appSecret = this.findAppSecret(appKey);
        String line = appKey + appSecret + time;

        String md5 = DigestUtils.md5DigestAsHex(line.getBytes());
        if (StringUtil.equalsIgnoreCase(md5, sig)) {
            return true;
        }

        log.error("#83 authorizationDecoded=" + authorizationDecoded + ", authorization=" + authorization + ", sig=" + sig + ", str=" + line + ", md5=" + md5 + ", appSecret=" + appSecret);
        return false;
    }

    private String toJson(PhoneApiResponse response) {
        if (response instanceof QueryAgentStateResponse) {
            return this.queryAgentStateResponseToJson((QueryAgentStateResponse) response);
        }

        if (response instanceof PhoneApiResponse) {
            return this.phoneApiResponseToJson((PhoneApiResponse) response);
        }

        throw new RuntimeException("#77 response=" + response);
    }

    private String phoneApiResponseToJson(PhoneApiResponse response) {
        return JSON.toJSONString(response);
    }

    private String queryAgentStateResponseToJson(QueryAgentStateResponse response) {
        List<String> agents = new ArrayList<String>();
        for (Agent agent : response.getAgents()) {
            Integer stateInt = (null == agent || null == agent.getState()) ? null : agent.getState().toInt();
            agents.add("{\"state\":\"" + stateInt + "\",\"id\":\"" + agent.getId() + "\",\"number\":\"" + agent.getNumber() + "\",\"type\":\"" + agent.getType() + "\"}");
        }

        return "{\"statusCode\":\"" + response.getStatusCode() + "\",\"agents\":{\"agent\":[" + StringUtil.join(agents, ", ") + "]}}";
    }

    private AgentOnWorkRequest agentOnWorkRequest(HttpServletRequest request) {
        String requestBody = Mvcs.getRequestBody(request);

        XmlObject xmlObject = Xml.parseString(requestBody);
        XmlObject requestNode = xmlObject.getChildNodeByName("Request");

        String appId = requestNode.getChildNodeTextContentByName("Appid");

        XmlObject agentOnWork = requestNode.getChildNodeByName("AgentOnWork");
        String number = agentOnWork.getAttributeValue("number"); // sip 号
        String agentId = agentOnWork.getAttributeValue("agentid"); // 示忙时会用
        String agentType = agentOnWork.getAttributeValue("agenttype"); // 队列名
        String remark = agentOnWork.getAttributeValue("remark"); // 备注
		String merchantId = agentOnWork.getAttributeValue("merchantId"); //商家ID

        AgentOnWorkRequest agentOnWorkRequest = new AgentOnWorkRequest() //
                .setAppId(appId) //
                .setAgentId(agentId) //
                .setAgentType(agentType) //
                .setRemark(remark)
				.setMerchantId(merchantId)
                .setNumber(number);

        log.info("#162 agentOnWorkRequest, requestBody=" + requestBody);

        return agentOnWorkRequest;
    }

    private AgentOffWorkRequest agentOffWorkRequest(HttpServletRequest request) {
        String requestBody = Mvcs.getRequestBody(request);

        XmlObject xmlObject = Xml.parseString(requestBody);
        XmlObject requestNode = xmlObject.getChildNodeByName("Request");

        String appId = requestNode.getChildNodeTextContentByName("Appid");

        XmlObject agentOffWork = requestNode.getChildNodeByName("AgentOffWork");
        String number = agentOffWork.getAttributeValue("number"); // sip 号
        String agentId = agentOffWork.getAttributeValue("agentid"); // 示忙时会用

        AgentOffWorkRequest agentOffWorkRequest = new AgentOffWorkRequest() //
                .setAppId(appId) //
                .setAgentId(agentId) //
                .setNumber(number);

        log.info("#184 agentOffWorkRequest, requestBody=" + requestBody);

        return agentOffWorkRequest;
    }

    private AgentReadyRequest agentReadyRequest(HttpServletRequest request) {
        String requestBody = Mvcs.getRequestBody(request);

        XmlObject xmlObject = Xml.parseString(requestBody);
        XmlObject requestNode = xmlObject.getChildNodeByName("Request");

        String appId = requestNode.getChildNodeTextContentByName("Appid");

        XmlObject agentReady = requestNode.getChildNodeByName("AgentReady");
        String agentId = agentReady.getAttributeValue("agentid");
        String state = agentReady.getAttributeValue("state"); // true表示状态更新为准备就绪，false表示状态更新为准备中，默认值为true

        AgentReadyRequest agentReadyRequest = new AgentReadyRequest() //
                .setAppId(appId) //
                .setAgentId(agentId) //
                .setState(state);

        log.info("#207 agentReadyRequest, requestBody=" + requestBody);

        return agentReadyRequest;
    }
    private BreakFileRequest breakFileRequest(HttpServletRequest request) {
        String requestBody = Mvcs.getRequestBody(request);
        XmlObject xmlObject = Xml.parseString(requestBody);

        XmlObject _request = xmlObject.getChildNodeByName("Request");
        String appId = _request.getChildNodeTextContentByName("Appid");

        XmlObject queryAgentState = _request.getChildNodeByName("BreakFile");
        String agentId = queryAgentState.getAttributeValue("agentid");
        String callId = queryAgentState.getAttributeValue("callid");

        BreakFileRequest breakFileRequest = new BreakFileRequest() //
                .setAppId(appId) //
                .setAgentId(agentId) //
                .setCallId(callId);

        log.info("#248 requestBody=" + requestBody + ", xmlObject=" + xmlObject + ", breakFileRequest=" + breakFileRequest);

        return breakFileRequest;
    }

    private IvrDialRequest ivrDialRequest(HttpServletRequest request) {
        String requestBody = Mvcs.getRequestBody(request);
        XmlObject xmlObject = Xml.parseString(requestBody);

        XmlObject _request = xmlObject.getChildNodeByName("Request");
        XmlObject _dial = _request.getChildNodeByName("Dial");

        String number = _dial.getAttributeValue("number"); // 被叫号 13699466308
        String appId = _request.getChildNodeTextContentByName("Appid");
        String userdata = _dial.getAttributeValue("userdata");
        String record = _dial.getAttributeValue("record");
        String disnumber = _dial.getAttributeValue("disnumber");

        IvrDialRequest ivrDialRequest = new IvrDialRequest() //
                .setAppId(appId) //
                .setUserdata(userdata) //
                .setRecord(record) //
                .setDisnumber(disnumber) //
                .setNumber(number);

        log.info("#229 ivrDialRequest, requestBody=" + requestBody);

        return ivrDialRequest;
    }

    private AgentServiceEndRequest agentServiceEndRequest(HttpServletRequest request) {
        String requestBody = Mvcs.getRequestBody(request);
        XmlObject xmlObject = Xml.parseString(requestBody);

        XmlObject _request = xmlObject.getChildNodeByName("Request");
        String appId = _request.getChildNodeTextContentByName("Appid");

        XmlObject queryAgentState = _request.getChildNodeByName("AgentServiceEnd");
        String agentId = queryAgentState.getAttributeValue("agentid");
        String callId = queryAgentState.getAttributeValue("callid");

        AgentServiceEndRequest agentServiceEndRequest = new AgentServiceEndRequest() //
                .setAppId(appId) //
                .setAgentId(agentId) //
                .setCallId(callId);

        log.info("#248 requestBody=" + requestBody + ", xmlObject=" + xmlObject + ", agentServiceEndRequest=" + agentServiceEndRequest);

        return agentServiceEndRequest;
    }

    private QueryAgentStateRequest queryAgentStateRequest(HttpServletRequest request) {
        String requestBody = Mvcs.getRequestBody(request);
        XmlObject xmlObject = Xml.parseString(requestBody);

        XmlObject _request = xmlObject.getChildNodeByName("Request");
        String appId = _request.getChildNodeTextContentByName("Appid");

        XmlObject queryAgentState = _request.getChildNodeByName("QueryAgentState");
        String agentId = queryAgentState.getAttributeValue("agentid");

        QueryAgentStateRequest queryAgentStateRequest = new QueryAgentStateRequest() //
                .setAppId(appId) //
                .setAgentId(agentId);

        log.info("#267 requestBody=" + requestBody + ", xmlObject=" + xmlObject + ", queryAgentStateRequest=" + queryAgentStateRequest);

        return queryAgentStateRequest;
    }


}
